const bigInt = require('big-integer');
const forge = require('node-forge');
// 消息集（对每个可能结果都有选票），每个 MessageSet 有 POSSIBLE_TICKET_NUM 个选票
class MessageSet {
    // 构造函数
    constructor(ticket) {
        this.ticket = ticket;
        this.id = new Array(this.ticket.length);
        this.id[0] = Math.floor(Math.random() * 1000000000); // 如果不只是 Yes 和 No 的话，那么每个消息集里的所有选票需要用一个识别号，这样服务器才能判断是否重复投同一个消息集中的选票
        for (var i = 0; i < this.ticket.length; ++i) {
            this.id[i] = this.id[0];
        }
    }

    /**
     * @param i 票在 MessageSets 中的索引下标
     * @return 大整数形式的 message（票），有识别号和票的内容
     */
    generateMessageFromTicketIndex(i) {
        var str = this.id[i].toString();
        str = str.padStart(15, '0'); // 15 位 10 进制数足够 2^48 的数量级了

        str = (this.ticket[i].toString() + str).padStart(30, '0');
        return new bigInt(str, 10);
    }
    /**
     * 生成该 MessageSet 的隐蔽
     * @param blindingFactor 盲因子
     * @param rsaE RSA 公钥（指数）
     * @param rsaN RSA 公钥（模）
     */
    blindMessageSet(blindingFactor, rsaN, rsaE) {
    var messages = new Array(this.ticket.length); // 大整数的数组
        for (var i = 0; i < this.ticket.length; ++i) {
            var m = this.generateMessageFromTicketIndex(i);
            //System.out.println("DEBUG: generateMessageFromTicketIndex returns " + m.toString());
            /*byte[] byteArray = m.toByteArray();
            byte[] lowEnd = new byte[8];
            System.arraycopy(byteArray, 0, lowEnd, 0, 8);
            byte[] highEnd = new byte[] {0,0,0,0,0,0,0,0};
            System.arraycopy(byteArray, 8, highEnd, 0, Math.min(8, byteArray.length - 8));
            long originalId = Longs.fromByteArray(lowEnd);
            long originalTicket = Longs.fromByteArray(highEnd);*/
            /*if (byteArray[0] == 0) {
                byte[] tmp = new byte[byteArray.length - 1];
                System.arraycopy(byteArray, 1, tmp, 0, tmp.length);
                byteArray = tmp;
            }*/
            //System.out.println("Debug: length of byteArray="+byteArray.length);

            /*for (int j = 0; j < 8; ++j) {
                originalId |= ((byteArray[j] << (j * 8)) & 0xFF);
            }*/

            /*try {
                for (int j = 0; j < 8; ++j) {
                    originalTicket |= ((byteArray[8 + j] << (j * 8)) & 0xFF);
                }
            } catch (ArrayIndexOutOfBoundsException e) {
                System.out.println("Out of bound.");
            }*/
            //System.out.println("Debug: before blind: originalTicket="+originalTicket);
            // debug end
            // 识别号和票的内容组成的 Message 被送去隐蔽（盲化）
            messages[i] = bigInt(blindingFactor.toString(), 10).modPow(rsaE, rsaN).multiply(m).mod(rsaN).toString(10);
        }
        return messages;
    }

}
// 盲化后的信息集，是盲签名时发送的请求
class BlindSignatureRequest {
    constructor(uid, blindMessage) {
        this.uid = uid;
        this.blindMessage = blindMessage;
    }
}
export default class Voter {
    constructor(userId, ticket) {
        console.log("userid=",userId, " ticket=", ticket);
        this.messageSets = new Array(10); // MessageSet 类型数组
        for (var i = 0; i < 10; ++i) {
            this.messageSets[i] = new MessageSet(ticket);
        }
        this.blindingFactors = new Array(10); // 大整数型数组
        for (var i = 0; i < 10; ++i) {
            this.blindingFactors[i] = 0;
        }
        this.userId = userId;
        this.ticket = ticket;
    }
/** 产生该候选人所有 10 个 MessageSet 的盲签名隐蔽（盲化后的信息）
 * @return BlindSignatureRequest 类型的数组
 */
generateBlindMessageSets(/*BigInteger*/ rsaN, /*BigInteger*/ rsaE) {
    var blindSiguatureRequests = new Array(10); // BlindSignatureRequest 类型数组
        for (var i = 0; i < 10; ++i) {
            forge.prime.generateProbablePrime(24, (err, num) => {
                this.blindingFactors[i] = num; // num 实际上是大整数
            });
            console.log('random prime',  this.blindingFactors[i].toString());
            blindSiguatureRequests[i] = new BlindSignatureRequest(this.userId, this.messageSets[i].blindMessageSet(this.blindingFactors[i], rsaN, rsaE));
        }
        return blindSiguatureRequests;
    }

/**
 * @param chosenIndex 是个整数，含义是服务器选中的 MessageSet 的下标
 * @param signedMessage 大整数数组，服务器盲签名后的 Message
 * @return 该 MessageSet 的原始签名（去盲化），实质上是个选票（大整数）构成的数组
 */
unblindOneMessageSet(/*BigInteger[]*/ signedMessage, /*BigInteger*/ rsaN, /*BigInteger*/ rsaE, chosenIndex) {
    var originalSignature = new Array(this.ticket.length); // 大整数数组
        // 找出选了哪个 MessageSet
        /*var chosenIndex;
        for (chosenIndex = 0; chosenIndex < 10; ++chosenIndex) {
            // var byteArray = new Array(); // byte[]
            var str;
            try {
                console.log("Trying blindingFactors["+chosenIndex+"]="+this.blindingFactors[chosenIndex].toString());
                str = bigInt(signedMessage[0], 10).multiply(bigInt(this.blindingFactors[chosenIndex].toString(), 10).modInv(rsaN)).mod(rsaN).modPow(rsaE, rsaN).toString();//.toByteArray();
            } catch (e) {
                // 此时不存在乘法逆元，说明不是这个 MessageSet
                console.log("There is no mod inverse!");
                console.log(e);
                continue;
            }
        // var lowEnd = new byte[8];
            // System.arraycopy(byteArray, 0, lowEnd, 0, 8);
        // var highEnd = new byte[8];// {0,0,0,0,0,0,0,0};
            // for (var i = 0; i < 8; ++i) {
                // highEnd[i] = 0;
            // }
            // System.arraycopy(byteArray, 8, highEnd, 0, Math.min(8, byteArray.length - 8));
            if (str.length != 30) {
                str = str.padStart(30, '0');
            }
            var originalId = new bigInt(str.substring(15, 30), 10); // Longs.fromByteArray(lowEnd);
            var originalTicket = new bigInt(str.substring(0, 15), 10);
        // var originalId = Longs.fromByteArray(lowEnd);
        // var originalTicket = Longs.fromByteArray(highEnd);
            // if (byteArray[0] == 0) {
            // var tmp = new byte[byteArray.length - 1];
                // System.arraycopy(byteArray, 1, tmp, 0, tmp.length);
                // byteArray = tmp;
            // }
            
            if (originalTicket == ticket[0]) break;
            console.log("originalTicket", originalTicket)
        }
        if (chosenIndex == 10) {
            console.log("Error! can't find which MessageSet has been signed.");
        }*/
        for (var i = 0; i < this.ticket.length; ++i) {
            originalSignature[i] = bigInt(signedMessage[i], 10).multiply(bigInt(this.blindingFactors[chosenIndex].toString(),10).modInv(rsaN)).mod(rsaN); // 原始签名
        // TODO: 这里应该验证服务器发回的选票的完整性
        /*BigInteger*/var originalMessage = originalSignature[i].modPow(rsaE, rsaN);
        //System.out.println("Voter: received from Authority originalMessage="+originalMessage.toString());
        // originalMessage.equals( generateMessageFromTicketIndex(i));
        var str = originalMessage.toString();
        if (str.length != 30) {
            str = str.padStart(30, '0');
        }
        var originalId = new bigInt(str.substring(15, 30), 10);
        var originalTicket = new bigInt(str.substring(0, 15), 10);
        }
        return originalSignature;
    }

/**
 * 服务器获取 10 个里面的 9 个盲签名
 * TODO: 客户端记录下服务器是不是调用了 9 次，防止服务器窥探
 */
/*public long*/ getBlindingFactor(/*int*/ messageSetIndex) {
        return this.blindingFactors[messageSetIndex];
    }
}